package com.clusterswisdom.horn.control;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.AsyncContext;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.clusterswisdom.horn.api.db.DbUtil;
import com.clusterswisdom.horn.api.event.BaseProcessor;
import com.clusterswisdom.horn.api.ioc.HornAction;
import com.clusterswisdom.horn.api.ioc.HornResponse;
import com.clusterswisdom.horn.api.ioc.api.ApiConfig;
import com.clusterswisdom.horn.api.ioc.api.HornConfig;

public class RequestProcess extends BaseProcessor implements Runnable {
	
	public static final String REQUEST_PARAM = "requestData";
	
	private String contentPath;
	
	private AsyncContext asynContext;
	
	public RequestProcess(String contentPath, AsyncContext asynContext) {
		this.contentPath = contentPath;
		this.asynContext = asynContext;
	}

	public void excute(AsyncContext asyncContext) {
		synchronized (this) {
			this.asynContext = asyncContext;
		}
	}

	@Override
	public void run() {
		try {
			String[] requestParam = splitRequest(asynContext.getRequest());
			if (requestParam == null || requestParam.length != 3) {
				sendError("request uri formate error.");
				return;
			}
			
			String requestData = asynContext.getRequest().getParameter(REQUEST_PARAM);
			if (requestData == null) {
				sendError("can not get request data");
				return;
			}
			
			processRequest(requestParam, formateParam(requestData));
			
		} finally {
			asynContext.complete();
			
		}
	}
	
	private void processRequest(String[] requestParam, JSONObject requestData) {
		ApiConfig apiConfig = HornConfig.getConfig().getApiConfig(requestParam[0], requestParam[1], requestParam[2]);
		if (apiConfig.isLog()) {
			saveRequestToDb(requestParam[0], requestData);
		}
		
		HornAction action = apiConfig.getAction();
		if (action == null) {
			sendError("can not find api " + requestParam[1] + "/" + requestParam[2] + " for channel " + requestParam[0]);
			
		} else {
			try {
				HornResponse response = super.process(apiConfig, requestData);
				Object responseData = super.processResponse(apiConfig.getResponse(), response);
				sendResponse(responseData);
				
			} catch (Exception e) {
				e.printStackTrace();
				sendError(e.getMessage());
				
			}
			
		}
	}
	
	private void sendError(String message) {
		sendStatus("1", message);
	}
	
	private void sendResponse(Object response) {
		String jsonString = JSON.toJSONString(response, SerializerFeature.QuoteFieldNames, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.UseISO8601DateFormat);
		asynContext.getResponse().setContentType("application/json;charset=UTF-8");
		try {
			asynContext.getResponse().getWriter().write(jsonString);
			asynContext.getResponse().getWriter().flush();
			
		} catch (IOException e) {
			e.printStackTrace();
			
		} 
	}
	
	private void sendStatus(String code, String message) {
		Map<String, String> response = new HashMap<String, String>();
		response.put("code", code);
		response.put("message", message == null ? "" : message);
		sendResponse(response);
	}
	
	private JSONObject formateParam(String requestData) {
		return JSON.parseObject(requestData);
	}
	
	private String[] splitRequest(ServletRequest request) {
		String requestUri = ((HttpServletRequest)request).getRequestURI().replaceAll(contentPath, "");
		int index = requestUri.lastIndexOf(".");
		requestUri = requestUri.substring(1, index);
		return requestUri.split("[/]");
	}
	
	private void saveRequestToDb(String channel, JSONObject param) {
		String ip = asynContext.getRequest().getRemoteAddr();
		String url = ((HttpServletRequest)asynContext.getRequest()).getRequestURI();
		
		DbUtil.getUtil().saveLog(channel, ip, url, JSON.toJSONString(param));
	}
}